Cloudflare Tunnel + SSH 内网穿透指南

本文介绍如何通过 Cloudflare Tunnel 和 cloudflared 服务,从公网任意位置安全地建立 SSH 连接。以下内容以「处于公网的笔记本电脑和处于内网的树莓派」为例。此方案无需公网 IP、端口映射或动态 DNS,只需要一个绑定了 Cloudflare Tunnel 的域名。


🚩前提条件

  • 一个已注册并接入 Cloudflare 的域名(如 hoigin.cn
  • 一台运行 Raspberry Pi OS 的树莓派(内网环境)
  • 一台 Windows 笔记本(用于发起 SSH 连接)

🚇步骤一:在树莓派上配置 Cloudflare Tunnel

1. 安装 cloudflared

为了使用 Cloudflare 提供的内网穿透服务,首先要在树莓派上安装可以向内网穿透隧道收发数据的客户端 Cloudflared。

bash
1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
                12
                13
# 进入用户目录
                cd ~
                
                # 下载适用于树莓派 64 位系统的 .deb 包
                wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb
                
                # 安装
                # -i 参数表示 install
                sudo dpkg -i cloudflared-linux-arm64.deb
                
                # 验证安装
                cloudflared --version
                # 输出类似:cloudflared version 2025.x.x

2. 登录并创建隧道

安装成功后,用以下命令在 Cloudflared 客户端登录账号。

bash
1
                2
# 浏览器授权,生成 cert.pem
                cloudflared tunnel login
  • 若树莓派有图形界面:自动打开浏览器,登录 Cloudflare
  • 若无图形界面:复制终端给出的 URL 到电脑浏览器完成授权
  • 成功后会在以下路径生成认证文件:~/.cloudflared/cert.pem

接着,使用以下命令创建一条名为 raspberrypi-tunnel 的隧道。

bash
1
cloudflared tunnel create raspberrypi-tunnel

创建成功后,此隧道的凭据文件将保存为 ~/.cloudflared/<UUID>.json ,记住此 <UUID> ,配置文件中需要用到。

3. 配置隧道路由

bash
1
cloudflared tunnel route dns raspberrypi-tunnel ssh.hoigin.cn

此命令在 Cloudflare DNS 中创建一条 Proxied CNAME 记录,将 ssh.hoigin.cn 绑定到隧道。接下来可以登录 Cloudflare 官网,点击「Cloudflare 控制台 - DNS - 记录」进行查看。

Note

CNAME、A 和 AAAA 是 DNS(Domain Name System),即域名系统中常见的记录类型,DNS 会根据记录类型将域名解析为 IP 地址或其他域名。常见的几种记录类型及 DNS 的处理方式如下表所示。

记录类型 全称 / 含义 DNS 的处理方式
A Address Record 域名 → IPv4 地址
AAAA IPv6 Address Record 域名 → IPv6 地址
CNAME Canonical Name Record 域名 → 另一个域名(别名)
MX Mail Exchange Record 指定接收邮件的邮件服务器
NS Name Server Record 指定该域名由哪些 DNS 服务器解析

在标准 DNS 语义中,这一操作表示 ssh.hoigin.cn 这个域名的别名是另一个域名 <UUID>.cfargotunnel.com ,当有用户查询 hoigin.cn 这个域名的时候,DNS 解析服务器就会去查询 <UUID>.cfargotunnel.com 这个域名的 IP 地址。但是,虽然这两个域名的关系在形式上是 CNAME,但 <UUID>.cfargotunnel.com 并不真的存在于公共 DNS 中,它只是 Cloudflare 内部用于标识隧道的一个逻辑端点名称。Cloudflare 看到它 CNAME 指向一个 .cfargotunnel.com 域名,就不会继续向外递归查询这个 CNAME 的 IP,而是直接返回 Cloudflare 自己的边缘 IP 地址,同时在内部标记这个请求属于隧道 <UUID> ,并查找是否有活跃的 Cloudflared 连接(来自树莓派),查询到有之后就通过已建立的加密隧道将 SSH 连接转发至用户端。

graph TD A[用户访问 ssh.hoigin.cn] A -->|DNS查询| B[请求到达Cloudflare</br>权威DNS服务器] B -->|DNS服务器返回边缘节点IP地址|C[请求到达Cloudflare<br/>边缘节点] C --> D[边缘节点发现</br>ssh.hoigin.cn对应</br>&ltUUID&gt.cfargotunnel.com] D --> E[内部查表发现</br>&ltUUID&gt.cfargotunnel.com<br/>对应隧道UUID</br>接着查找该UUID是否有<br/>活跃的cloudflared连接<br/>] E -->|有!来自树莓派!</br>通过已建立的加密隧道转发请求| F[请求到达树莓派上的</br>cloudflared] F --> G[转发树莓派的<br/>本地 SSH 端口] style A fill:#d7f3e3,stroke:#000,color:black style B fill:#d7f3e3,stroke:#000,color:black style C fill:#d7f3e3,stroke:#000,color:black style D fill:#d7f3e3,stroke:#000,color:black style E fill:#d7f3e3,stroke:#000,color:black style F fill:#d7f3e3,stroke:#000,color:black style G fill:#d7f3e3,stroke:#000,color:black

总之,到这一步就把内网穿透隧道和域名关联好了。

Tip

边缘节点(Edge Node),也称为接入点(Point of Presence,PoP),是在全球部署的服务器节点,用于就近处理用户请求。在现代互联网架构中是提升网站性能与安全的关键基础设施。截至 2025 年,Cloudflare 在超过 120 个国家和地区运营着 300 多个边缘节点,构成一个分布式的安全与加速网络。当用户访问使用 Cloudflare 的网站或通过 Tunnel 暴露的内网服务时,流量首先到达离用户最近的边缘节点,再由它负责安全过滤、缓存或通过加密隧道转发至源站。这种架构既提升了访问速度,又隐藏了真实服务器位置,增强了安全性。


4. 创建隧道配置文件

接下来使用前面记住的 <UUID> 来创建配置文件,放置在 ~/.cloudflared/config.yml 路径里,内容如下:

yaml
1
                2
                3
                4
                5
                6
tunnel: <UUID> # 替换为实际 UUID(不含 .json 后缀)
                credentials-file: /home/pi/.cloudflared/<UUID>.json # 替换为实际 UUID
                ingress:
                  - hostname: ssh.hoigin.cn # SSH连接用的域名
                    service: tcp://localhost:22 # 树莓派上的cloudflared负责转发至22端口,即SSH默认端口
                  - service: http_status:404 # 未匹配请求返回 404

5. 以系统服务运行隧道

在终端输入以下命令,在 systemd/system 路径下创建一项名为 cloudflared.service 的后台服务。

bash
1
sudo nano /etc/systemd/system/cloudflared.service

打开 cloudflared.service 文件,写入这项后台服务的配置,如下所示:

ini
1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
                12
                13
                14
                15
                16
                17
                18
                19
                20
                21
                22
                23
                24
                25
                26
                27
                28
                29
                30
[Unit]
                ; 服务的简要描述,显示在 systemctl status 等命令中
                Description=Cloudflare Tunnel for hoigin.cn
                
                ; 指定该服务在网络已就绪后再启动,确保 cloudflared 能正常联网
                After=network.target
                
                [Service]
                ; Type=exec 表示主进程就是 ExecStart 启动的程序(推荐用于 cloudflared)
                Type=exec
                
                ; 以普通用户 'pi' 身份运行服务,避免使用 root 提高安全性
                User=pi
                
                ; 启动命令:运行名为 raspberrypi-tunnel 的 Cloudflare 隧道
                ; 注意:cloudflared 会自动读取 ~/.cloudflared/ 下的配置和凭据
                ExecStart=/usr/bin/cloudflared tunnel run raspberrypi-tunnel
                
                ; 若服务异常退出(非零状态),则自动重启
                Restart=on-failure
                
                ; 重启前等待 5 秒,避免频繁崩溃导致资源浪费
                RestartSec=5
                
                ; 终止服务时仅杀死主进程(cloudflared),不杀其子进程(实际无子进程,此设置更安全)
                KillMode=process
                
                [Install]
                ; 设置服务启用(systemctl enable)后,在 multi-user.target(即常规多用户模式)下自动启动
                WantedBy=multi-user.target

写入保存好之后,在终端启用服务即可。

bash
1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
# 重新加载 systemd 配置文件
                sudo systemctl daemon-reload
                
                # 设置服务开机自启动
                sudo systemctl enable cloudflared
                
                # 启动服务
                sudo systemctl start cloudflared
                
                # 检查服务是否正常运行
                systemctl status cloudflared

🛠️步骤二:在笔记本上配置客户端

在 Windows Powershell 中配置

1. 安装 cloudflared

以管理员身份打开 PowerShell,运行:

powershell
1
winget install Cloudflare.cloudflared

2. 登录 Cloudflare 账户

powershell
1
cloudflared login

浏览器会自动打开,完成授权后生成 %USERPROFILE%\.cloudflared\cert.pem(生成的 cert.pem 文件有可能直接下载到默认文件夹,需要手动复制粘贴到这个路径)。

3. 生成 SSH 配置

powershell
1
cloudflared access ssh-config --hostname ssh.hoigin.cn

输出类似:

text
1
                2
                3
Host ssh.hoigin.cn
                  ProxyCommand C:\Users\ASUS\AppData\Local\Microsoft\WinGet\Packages\Cloudflare.cloudflared_...\cloudflared.exe access ssh --hostname %h
                  User pi

4. 写入 SSH 配置文件

编辑 C:\Users\ASUS\.ssh\config,添加上述内容。

在 Linux Shell 中配置

1. 安装 cloudflared

安装流程与在服务器端的一样,如下所示:

bash
1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
                12
                13
# 进入用户目录
                cd ~
                
                # 下载适用于树莓派 64 位系统的 .deb 包
                wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb
                
                # 安装
                # -i 参数表示 install
                sudo dpkg -i cloudflared-linux-arm64.deb
                
                # 验证安装
                cloudflared --version
                # 输出类似:cloudflared version 2025.x.x

2. 登录 Cloudflare 账户

powershell
1
cloudflared login

浏览器会自动打开,完成授权后生成 cert.pem 文件,接着需要手动复制粘贴到 ~/.cloudflared/cert.pem 这个位置。接着,为了让 cert.pem 文件中的私钥不被其他用户读取,需要对此文件设置权限,如下所示:

bash
1
chmod 600 ~/.cloudflared/cert.pem

运行测试命令,验证 cloudflared 是否能读取证书:

bash
1
                2
                3
                4
                5
cloudflared tunnel --help
                # 如果此命令没报错,说明 cloudflared 已安装。
                
                cloudflared tunnel list
                # 如果此命令返回隧道列表(或空列表但无错误),说明 cert.pem 配置成功

Important

这里说的 cert.pem 是一个 TLS 客户端证书,用于客户端的 cloudflared 与 cloudflare 边缘节点之间的身份验证。客户端的 cloudflared 需要用私钥签名,然后 cloudflare 边缘节点用公钥来验证其身份。这个过程与 SSH 连接无关。如果后续使用密钥对进行 SSH 连接的话,整个过程可以用一个比喻来理解:Cloudflare Tunnel 相当于快递公司的运输路线,SSH 密钥对相当于目的地的门锁和钥匙,而 cloudflared 相当于快递员,需要有工作证(Cloudflare 证书,即 cert.pem 文件)才能接单。

3. 写入 SSH 配置文件

接下来可以配置 ~/.ssh/config,让 SSH 自动通过 cloudflared 转发。首先用 vim 编辑器打开配置文件:

bash
1
vim ~/.ssh/config

然后写入配置文件内容:

text
1
                2
                3
                4
Host ssh.hoigin.cn
                    HostName ssh.hoigin.cn
                    User pi
                    ProxyCommand cloudflared access ssh --hostname %h

🖇️步骤三:连接测试

在 Windows 系统的 PowerShell 中或 Linux 的终端中执行:

powershell
1
                2
                3
ssh pi@ssh.hoigin.cn
                # 或者用以下命令
                ssh ssh.hoigin.cn

首次连接有可能会弹出浏览器,登录 Cloudflare 后自动建立加密隧道,成功进入树莓派终端。

Caution

Windows系统的上的 cloudflared 不是以系统服务的形式运行的,每次运行 ssh pi@ssh.hoigin.cn 时,cloudflared 会自动启动一个子进程进行 SSH 连接;连接断开后,该进程自动结束。

🔑步骤四:配置密钥对(可选)

1. 生成密钥对

下面的配置过程以 Linux 系统为例。首先,用以下命令生成 SSH 密钥对:

bash
1
                2
                3
# -t 即 type,指定密钥的类型
                # ed25519 是 OpenSSH 官方推荐的一种公钥加密算法,是基于Edwards-curve Digital Signature Algorithm (EdDSA) 的一种具体实现,使用 Curve25519 椭圆曲线
                ssh-keygen -t ed25519

接下来会看到类似这样的交互:

text
1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
                12
                13
                14
                15
                16
                17
                18
                19
                20
Generating public/private ed25519 key pair.
                Enter file in which to save the key (/home/you/.ssh/id_ed25519): [直接回车]
                Enter passphrase (empty for no passphrase): [直接回车,除非你需要额外保护]
                Enter same passphrase again: [回车]
                Your identification has been saved in /home/you/.ssh/id_ed25519
                Your public key has been saved in /home/you/.ssh/id_ed25519.pub
                The key fingerprint is:
                SHA256:kIMgstOypcKKdlB9pqGK5GTCeKbAFgkk9MsPksD9dU4 ubuntu@hoigin
                The key's randomart image is:
                +--[ED25519 256]--+
                |Bo.              |
                |=++... .         |
                |=+o+.o++ E       |
                |**= + *o+        |
                |B%o= o  S.       |
                |&++ o            |
                |=+ . .           |
                |. .              |
                |                 |
                +----[SHA256]-----+

这里没有设置 passphrase 是因为要实现无交互地使用密钥对进行 SSH 连接。未来如果需要实现自动化脚本的话,也必须要实现「无交互」。另外,还要确保私钥权限为 600:

bash
1
chmod 600 ~/.ssh/id_ed25519

Note

交互过程中出现的 key fingerprint ,即指纹,是对公钥内容进行哈希(hash)后得到的一个短字符串。它的作用是快速、唯一地标识一个 SSH 公钥(比看一长串 base64 字符更方便)。当你第一次 SSH 连接到一个新服务器时,SSH 客户端会显示服务器的公钥指纹,并问你是否信任:

text
1
                    2
                    3
1The authenticity of host 'example.com (1.2.3.4)' can't be established.
                    2ECDSA key fingerprint is SHA256:AbCdEfGhIjKlMnOpQrStUvWxYz1234567890abc.
                    3Are you sure you want to continue connecting (yes/no)?

你可以通过其他可信渠道(如控制台、文档)核对这个指纹是否一致,防止连接到假冒的服务器。

Note

交互过程中出现的 randomart image ,即随机艺术图,是一个将密钥指纹可视化为 ASCII 艺术图案的功能,目的是让人更容易肉眼识别和记忆密钥指纹。人对图像的记忆比对字符串更强。如果你经常连接某台服务器,看到它的 RandomArt 图「像一只鸟」,下次如果图变了(比如变成「像一把刀」),你就知道公钥可能被篡改了!

2. 上传公钥至树莓派

使用以下命令进行上传:

bash
1
                2
# 替换 your-tunnel-host 为你的实际主机名(如 ssh.hoigin.cn)
                ssh-copy-id -i ~/.ssh/id_ed25519.pub pi@your-tunnel-host

系统会提示你输入一次树莓派的密码,之后自动在树莓派创建 ~/.ssh/ 目录并将将公钥追加到 ~/.ssh/authorized_keys,然后设置正确权限(700 / 600)。成功后可以看到输出:

text
1
                2
Number of key(s) added: 1
                Now try logging into the machine...

此外,还可以打开树莓派的终端检查公钥是否已经添加至 ~/.ssh/authorized_keys 中。

3. 改写 SSH 配置文件

打开 ~/.ssh/config 文件后,加入指定私钥的配置信息:

text
1
                2
                3
                4
                5
                6
Host rpi
                    HostName ssh.hoigin.cn
                    User pi
                    IdentityFile ~/.ssh/id_ed25519  # 指定私钥
                    IdentitiesOnly yes              # 只用这个私钥,避免其他密钥干扰
                    ProxyCommand cloudflared access ssh --hostname %h

之后再重试「🖇️步骤三:连接测试」即可。


📚说明

  • 所有流量均通过 Cloudflare 全球网络加密传输,不暴露树莓派真实 IP。
  • 每次连接需通过 Cloudflare Access 身份认证(支持邮箱、2FA 等策略)。
  • 该方案适用于任何内网设备,不仅限于 SSH(可扩展至 HTTP、RDP 等协议)。
  • 「🔑步骤四:配置密钥对(可选)」中所生成的私钥可以放到 Windows、MacOS、iOS、Android 等其它平台上,实现免密码的 SSH 连接。